`timescale 1ns / 1ps
module rhdl_pico_ctl(CLK_I, READ_I, WRITE_I, ADDR_I, DATA_I, MUX_DATA_I, CLK_EN_O, RESET_O, START_O, WRITE_O, DATA_O, WRITE_ADDR_O, READ_ADDR_O, WRITE_DATA_O);
    input CLK_I;
    input READ_I;
    input WRITE_I;
    input [31:0] ADDR_I;
    input [15:0] DATA_I;
    input [15:0] MUX_DATA_I;
    
    output CLK_EN_O;
    output RESET_O;
    output START_O;
    output WRITE_O;
    output [15:0] DATA_O;
    output [12:0] WRITE_ADDR_O;
    output [13:0] READ_ADDR_O;
    output [12:0] WRITE_DATA_O;

	reg CLK_EN_O;
	reg RESET_O;
	reg START_O;
	//reg WRITE_O;

	reg [12:0] WRITE_ADDR_O;
	
	`define IO_BASE_ADDR 32'h0B000000


reg [13:0] clk_count;
reg [15:0] data_reg_o;


wire select;
wire clk_stopped;
reg clk_no_stop;

assign select = (`IO_BASE_ADDR == ADDR_I);
assign clk_stopped = (clk_count == 14'b0);

always @(posedge CLK_I)
begin
	if (WRITE_I && select)
	begin
		CLK_EN_O <= 0;
		case (DATA_I[1:0])
		3:    //reset
		begin
			RESET_O <= 1;
			START_O <= 0;
			clk_count <= 8; //4; //8 JNA
			data_reg_o <= 16'h3;
			WRITE_ADDR_O <= WRITE_ADDR_O;
			clk_no_stop <= 0;
		end

		2: 	// read
		begin
			RESET_O <= RESET_O;
			START_O <= START_O;
			clk_count <= 0;
			data_reg_o <= MUX_DATA_I;
			WRITE_ADDR_O <= WRITE_ADDR_O;
			clk_no_stop <= 0;
		end

		1:		// start clock
		begin
			RESET_O <= 0;
			START_O <= 1;
			//clk_count <= DATA_I[15:2];
			clk_count[13:1] <= DATA_I[14:2];
			clk_count[0] <= 1'b0;
			data_reg_o <= 16'h1;
			WRITE_ADDR_O <= WRITE_ADDR_O;
			if (DATA_I[15:2] == 1024)
			begin
				clk_no_stop <= 1;
			end
			else
			begin
				clk_no_stop <= 0;
			end
		end
		
		0:   // write
		begin
			RESET_O <= RESET_O;
			START_O <= START_O;
			clk_count <= 0;
			clk_no_stop <= 0;
			if (DATA_I[2] == 0)
			begin
				data_reg_o <= 16'h4;
				WRITE_ADDR_O <= DATA_I[15:3];
			end
			else
			begin
				data_reg_o <= 16'h5;
				WRITE_ADDR_O <= WRITE_ADDR_O;
			end						
		end
		endcase
	end
	else
	begin
		clk_no_stop <= clk_no_stop;
		WRITE_ADDR_O <= WRITE_ADDR_O;
		data_reg_o <= data_reg_o;
		if (!clk_stopped)
		begin
			CLK_EN_O <= 1;
			if (clk_no_stop)
				clk_count <= 1;
			else
				clk_count <= clk_count - 1;
				
			START_O <= 0;
			RESET_O <= RESET_O;
			clk_no_stop <= clk_no_stop;
		end
		else
		begin
			CLK_EN_O <= 0;
			clk_count <= clk_count;
			clk_no_stop <= 0;
			START_O <= 0;
			RESET_O <= 0;
		end
	end
end


assign DATA_O = (READ_I && select) ? data_reg_o : 16'h0;
assign READ_ADDR_O = DATA_I[15:2];

assign WRITE_O = WRITE_I && select && (DATA_I[2:0] == 3'b100);
assign WRITE_DATA_O = DATA_I[15:3];

endmodule
